package nachos.threads;

import nachos.machine.*;

/**
 * Coordinates a group of thread queues of the same kind.
 *
 * @see nachos.threads.ThreadQueue
 */
public abstract class Scheduler {
    /**
     * Allocate a new scheduler.
     */
    public Scheduler() {
    }

    /**
     * 分配一个新的线程队列
     * 如果 transferPriority 为 true
     * 那么等待新队列的线程就把它们的“优先级”转移到可以访问到被队列保护的任何内容的线程
     * 这是用于部分解决优先级反转的机制
     *
     * <p>
     * 如果没有确定的线程拥有访问权限，那么这个参数应该为 false，表示优先级不应该被转移
     *
     * <p>
     * 处理器是个特例
     * 显然，向拥有处理器的线程提供优先级没有任何意义
     * 如果处理器等待队列已经被创建了，该参数应该为 false
     *
     * <p>
     * 否则，提供优先级是有用的
     * 例如，一个锁拥有确定的属主（持有所的线程），这个锁总是由获取它的同一线程释放
     * 通过向持有锁的线程提供优先级，可以帮助高优先级的线程等待锁
     * 因此，应该创建一个锁队列，并将此参数设置为 true
     *
     * <p>
     * 类似的，当线程在 join() 中休眠并等待目标线程完成时，休眠的线程应该将它的优先级提供给目标线程
     * 因此，一个 join 队列应该被创建，并将该参数设置为 true
     *
     * @param transferPriority  如果具有访问权限的线程应该从等待此队列的线程接收优先级，那么该参数为 true
     * @return 一个新的线程队列
     */
    public abstract ThreadQueue newThreadQueue(boolean transferPriority);

    /**
     * Get the priority of the specified thread. Must be called with
     * interrupts disabled.
     *
     * @param thread the thread to get the priority of.
     * @return the thread's priority.
     */
    public int getPriority(KThread thread) {
        Lib.assertTrue(Machine.interrupt().disabled());
        return 0;
    }

    /**
     * Get the priority of the current thread. Equivalent to
     * <tt>getPriority(KThread.currentThread())</tt>.
     *
     * @return the current thread's priority.
     */
    public int getPriority() {
        return getPriority(KThread.currentThread());
    }

    /**
     * Get the effective priority of the specified thread. Must be called with
     * interrupts disabled.
     *
     * <p>
     * The effective priority of a thread is the priority of a thread after
     * taking into account priority donations.
     *
     * <p>
     * For a priority scheduler, this is the maximum of the thread's priority
     * and the priorities of all other threads waiting for the thread through a
     * lock or a join.
     *
     * <p>
     * For a lottery scheduler, this is the sum of the thread's tickets and the
     * tickets of all other threads waiting for the thread through a lock or a
     * join.
     *
     * @param thread the thread to get the effective priority of.
     * @return the thread's effective priority.
     */
    public int getEffectivePriority(KThread thread) {
        Lib.assertTrue(Machine.interrupt().disabled());
        return 0;
    }

    /**
     * Get the effective priority of the current thread. Equivalent to
     * <tt>getEffectivePriority(KThread.currentThread())</tt>.
     *
     * @return the current thread's priority.
     */
    public int getEffectivePriority() {
        return getEffectivePriority(KThread.currentThread());
    }

    /**
     * Set the priority of the specified thread. Must be called with interrupts
     * disabled.
     *
     * @param thread   the thread to set the priority of.
     * @param priority the new priority.
     */
    public void setPriority(KThread thread, int priority) {
        Lib.assertTrue(Machine.interrupt().disabled());
    }

    /**
     * Set the priority of the current thread. Equivalent to
     * <tt>setPriority(KThread.currentThread(), priority)</tt>.
     *
     * @param priority the new priority.
     */
    public void setPriority(int priority) {
        setPriority(KThread.currentThread(), priority);
    }

    /**
     * If possible, raise the priority of the current thread in some
     * scheduler-dependent way.
     *
     * @return <tt>true</tt> if the scheduler was able to increase the current
     * thread's
     * priority.
     */
    public boolean increasePriority() {
        return false;
    }

    /**
     * If possible, lower the priority of the current thread user in some
     * scheduler-dependent way, preferably by the same amount as would a call
     * to <tt>increasePriority()</tt>.
     *
     * @return <tt>true</tt> if the scheduler was able to decrease the current
     * thread's priority.
     */
    public boolean decreasePriority() {
        return false;
    }
}
